#pragma once
#include <iostream>
#include <functional>
#include <strings.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include "log.hpp"
#include "protocol.hpp"

#define ANY_IP "0,0,0,0"

class httpserve
{
    typedef std::function<void(request &req, response &rep)> func_t;
    void Handle_func(int &sock)
    {
        char inbuffer[4096];
        // 接受信息
        int size = recv(sock, &inbuffer, sizeof(inbuffer) - 1, 0);
        if (size < 0)
        {
            logMessage(ERROR, "RECV ERROR");
            exit(-1);
        }
        inbuffer[size] = 0;
        logMessage(NORMAL, "RECV SUCCESS");
        request req(inbuffer);
        response rep;
        _func(req, rep);
        // 处理并发送信息
        send(sock, rep.outbuffer.c_str(), rep.outbuffer.size(), 0);
        return;
    }

public:
    httpserve(func_t func, uint16_t serve_port, std::string serve_ip = ANY_IP)
        : _listen_sock(-1), _serve_port(serve_port), _serve_ip(serve_ip), _func(func)
    {
    }

    void init()
    {
        _listen_sock = socket(AF_INET, SOCK_STREAM, 0);
        if (_listen_sock == -1)
        {
            logMessage(ERROR, "SOCKET ERROR");
            exit(-1);
        }

        sockaddr_in local_addr;
        bzero(&local_addr, sizeof(local_addr));
        local_addr.sin_family = AF_INET;
        local_addr.sin_port = htons(_serve_port);
        local_addr.sin_addr.s_addr = INADDR_ANY;

        if (bind(_listen_sock, (sockaddr *)&local_addr, sizeof(sockaddr_in)) < 0)
        {
            logMessage(ERROR, "BIND ERROR");
            exit(-1);
        }
        logMessage(NORMAL, "BIND SOCK SUCCESS");

        int ret = listen(_listen_sock, 5);
        if (ret == -1)
        {
            logMessage(ERROR, "LISTEN SOCK ERROR");
            exit(-1);
        }
        logMessage(NORMAL, "LISTEN SOCK SUCCESS");
    }

    void start()
    {
        for (;;)
        {
            /////////////////////
            socklen_t client_addr_len = sizeof(sockaddr_in);
            struct sockaddr_in client;
            int sock = accept(_listen_sock, (struct sockaddr *)&client, &client_addr_len);
            if (sock < 0)
            {
                logMessage(DEBUG, "ACCEPT SOCK ERROR");
                continue;
            }
            ////////////////////
            logMessage(NORMAL, "ACCEPT SOCK SUCCESS");
            pid_t child_pid = fork();
            if (child_pid == -1)
            {
                logMessage(ERROR, "FORK ERROR");
                exit(-1);
            }
            else if (child_pid == 0)
            {
                int ppid = fork();
                if (ppid > 0)
                    exit(-1);
                close(_listen_sock);
                Handle_func(sock);
                close(sock);
                exit(0);
            }
            waitpid(child_pid, nullptr, 0);
            close(sock);
        }
    }

    ~httpserve()
    {
    }

private:
    int _listen_sock;
    uint16_t _serve_port;
    std::string _serve_ip;
    func_t _func;
};
